module arm.i2c;

import chip;
import arm.misc;
import arm;

private enum bool hasBusPeriph = HasPeriph!("I2C1", "I2C2", "I2C3");

static if(hasBusPeriph):

import arm.bus;
//import arm.gpio;
import arm.utils;

interface MasterStream : MemoryStream
{
    void setTargetAddress(uint addr);
}


/// I2c 通讯接口模式选择标志
enum FlagMode
{
    None,           /// 无
    I2c,            /// I2C
    Smba,           /// SMBus
    SmbaHost,       /// SMBus Host
}

/**
* 外设基础操作接口
*/
static interface I2C(alias mPeri) 
{
    version(NONE) enum I2C1_Type* mBase = Peripherals.I2C1;
    else enum  mBase = mPeri;
    enum string IFName = __traits(identifier,mPeri);

    /// i2c freq
    enum FlagFreq
    {
        none
    }

    /**
    * I2C 配置结构体
    */
    struct I2C_Config
    {
        uint clockSpeed;        /// 时钟速度
        uint dutyCycle;         /// 占空比
        uint ownAddress1;       /// 自身地址1
        uint addressingMode;    /// 地址模式
        uint dualAddressMode;   /// 双地址模式
        uint ownAddress2;       /// 自身地址2
        uint generalCallMode;   /// 通用调用模式
        uint noStretchMode;     /// 不拉伸模式
    }
    //enum Conf = I2C_Config(5,5,5,5,5,5,5);

    static SpinLock_Struct mLock;   /// 锁

    
    /// 启用时钟
    static void ClkEnable() => (RCC.Power!(IFName~"EN")(1));
    /// 禁用时钟
    static void ClkDisable() => (RCC.Power!(IFName~"EN")(0));
    /// 判定时钟是否启用
    static bool ClkIsEnable() => (RCC.Power!(IFName~"EN")() == 1);
    /// 启用
    static void Enable() => (mBase.CR1.PE = 1);
    /// 禁用
    static void Disable() => (mBase.CR1.PE = 0);
    /// 是否启用
    static bool IsEnable() => (mBase.CR1.PE == 1);
    /// 重置IIC
    static void I2CReset()
    {
        mBase.CR1.SWRST = 1;
        mBase.CR1.SWRST = 0;
    }
 
    /// 设定工作速度
    static void SetSpeed(uint speed)
    {
        /// todo:逻辑顺序有问题,不应中断当前外设工作状态
        /*
        bool lastPE = mBase.CR1.PE;
        mBase.CR1.PE = 0;
        scope(exit) mBase.CR1.PE = lastPE;
        */
        //mBase.CR2.FREQ = speed;
        auto mFreq = speed/1000000u;            //mhz
        mBase.CR2.FREQ = mFreq;
        /// master模式下高电平时间
        /// todo : 公式还需查阅
        auto setl = (mFreq <= 1000000u) ?mFreq+1:((mFreq*300)/1000)+1;
        mBase.TRISE.TRISE = setl;

    }

    /// 设置频率
    //void SetFreq(uint freq);
    /// 发送停止位
    //void SendStop();
    
    /// 发字节
    //void SendByte(uint data);
    /// 收字节 
    //uint RecvByte();
    /// 是否忙
    static bool Busy() => (mBase.SR2.BUSY == 1);
    
    /**
    * 配置参数
    * Params:
    *  conf = 配置结构体
    *Examples: 
    ----
    config(conf); //运行时配置
    config!(conf)(); //编译时配置
    ----
    */
    static void Config(I2C_Config conf)
    {
        /*
        mBase.CR2.FREQ = conf.clockSpeed;
        mBase.CCR.DUTY = conf.dutyCycle;
        mBase.OAR1.ADD0 = conf.ownAddress1;
        mBase.OAR1.ADDMODE = conf.addressingMode;
        mBase.OAR2.ENDUAL = conf.dualAddressMode;
        mBase.OAR2.ADD2 = conf.ownAddress2;
        mBase.CR1.GCEN = conf.generalCallMode;
        mBase.CR1.NOSTRETCH = conf.noStretchMode;
        */
    }
    static void Config(I2C_Config conf)()
    {
        //mBase.CR2.FREQ = conf.clockSpeed;  // 需要考虑当前总线速度设置
        Disable();  // 禁用外设
        mBase.CCR.DUTY = conf.dutyCycle;
        mBase.OAR1 = 0x00;          // 清空原始值
        mBase.OAR2 = 0x00;

        

    }
    /// 接收缓冲区是否空
    static bool RxEmpty() => (mBase.SR1.RxNE() == 1);
    /// 发送缓冲区是否空
    static bool TxEmpty() => (mBase.SR1.TxE() == 1);
    /// 送入DR寄存器 8bit
    static void Write(ubyte data) => (mBase.DR = data);
    /// DR寄存器读出
    static ubyte Read() => (cast(ubyte)(mBase.DR&0xff));


    
    /// 
    pragma(crt_constructor,CrtPriority!(FlagCrt.Other,0))
    static this()
    {
        RCC.Power!(IFName~"EN")(1);
    }
}

/// 基础类,实现基础


/// I2C 通讯接口,主机模式
class I2C_Master(alias mPeri) : I2C!(mPeri),MasterStream
{
    // 保存控制寄存器
    uint mCCR;
    uint mCR1;
    uint mCR2;
    
    /// 本次使用对寄存器赋值,复用机制需要多线程考虑
    void InitReg()
    {
        /*
        mBase.CCR = mCCR;
        mBase.CR1 = mCR1;
        mBase.CR2 = mCR2;
        */
        mBase.OAR2 = 0x00;              /// 清空地址二寄存器
        mBase.CR1.ENGC = 0;             /// 通用调用模式
        mBase.CR1.NOSTRETCH = 0;        /// 不拉伸模式
    }
    /// 申请使用
    /// 释放

    

    /// todo: 应考虑超时
    size_t reads(void* dst,size_t len)
    {        
        /* 线程部分未生效,暂时放弃
        if(!mLock.tryLock(1000)) return 0;
        scope(exit) mLock.UnLock();
        */
        /// 实际读取字符数量
        size_t n = 0;
        while(len--)
        {
            // 等待接收缓冲区非空
            while(!RxEmpty()){}
            // 读取数据
            *cast(ubyte*)dst++ = Read();
            n++;
        }
        
        return n;
    }
    void writes(immutable(char)* src, size_t len)
    {
        while(len--)
        {
            while(!TxEmpty()){}
            Write(cast(ubyte)*src++);
        }
    }
    
    void setTargetAddress(uint addr)
    {
        

    }
    //--
    /// 设定目标地址


}

class I2C_None(alias mPeri) : I2C!(mPeri),PeriStream
{

    size_t read(void* dst,size_t n)
    {
        return 0;
    }

    void write(immutable(char)* src, size_t len)
    {
    }
}

alias I2c1 = I2C!(Peripherals.I2C1);



void test()
{
    I2c1 vi1;
    //vi1.read();
    //I2c1.read();
}

/*
final abstract class I2C(alias mPeri,I2C_Config Conf = I2C_Config.init)  : MMIOBus!(mPeri)
{
    version(none) enum I2C1_Type* mBase = Peripherals.I2C1;
    else enum  mBase = mPeri;

    static public{
        void Init()
        {
            
        }
    }

}

alias Timer1 = I2C!(Peripherals.I2C1,Conf);
*/